/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.easyedu.dictionary.api.importer.impl;

import eu.easyedu.dictionary.api.importer.DictionaryImporter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.cookies.InstanceCookie;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.util.RequestProcessor;

/**
 *
 * @author Michal HLavac <hlavki@hlavki.eu>
 */
public class DictionaryImporterManager implements FileChangeListener {

    private static final Logger log = Logger.getLogger(DictionaryImporterManager.class.getName());
    private static final String REMOTE_FS_FOLDER = "eu-easyedu-dictionary/Importers/";  // NOI18N
    private static DictionaryImporterManager instance = null;
    private static final String POSITION_ATTR = "position";
    private static final String INSTANCE_EXT = ".instance";
    private List<DictionaryImporter> importers;

    private DictionaryImporterManager() {
        doInit();
    }

    public static synchronized DictionaryImporterManager getDefault() {
        if (instance == null) {
            instance = new DictionaryImporterManager();
        }
        return instance;
    }

    private void initImporters() {
        FileObject folder = FileUtil.getConfigFile(REMOTE_FS_FOLDER);
        List<ImporterEntry> fsEntries = readImporter(folder);
        importers = getListOfImporters(fsEntries);
    }

    private List<DictionaryImporter> getListOfImporters(List<ImporterEntry> entries) {
        List<DictionaryImporter> result = new ArrayList<DictionaryImporter>();
        for (ImporterEntry entry : entries) {
            result.add(entry.getImporter());
        }
        return result;
    }

    public List<DictionaryImporter> getImporters() {
        return importers;
    }

    private synchronized void doInit() {
        initImporters();
    }

    private static DictionaryImporter instantiateImporter(FileObject fileObject) {
        try {
            DataObject dobj = DataObject.find(fileObject);
            InstanceCookie ic = dobj.getCookie(InstanceCookie.class);
            Object fsInstance = ic.instanceCreate();

            if (fsInstance instanceof DictionaryImporter) {
                return (DictionaryImporter) fsInstance;
            } else {
                return null;
            }
        } catch (IOException e) {
            log.log(Level.SEVERE, null, e);
        } catch (ClassNotFoundException e) {
            log.log(Level.SEVERE, null, e);
        }

        return null;
    }

    /** Read rules from system filesystem */
    private List<ImporterEntry> readImporter(FileObject folder) {
        List<ImporterEntry> fs = new LinkedList<ImporterEntry>();

        if (folder == null) {
            return fs;
        }

        Queue<FileObject> q = new LinkedList<FileObject>();

        q.offer(folder);

        while (!q.isEmpty()) {
            FileObject o = q.poll();

            o.removeFileChangeListener(this);
            o.addFileChangeListener(this);

            if (o.isFolder()) {
                q.addAll(Arrays.asList(o.getChildren()));
                continue;
            }

            if (!o.isData()) {
                continue;
            }

            String name = o.getNameExt().toLowerCase();
            Integer position = (Integer) o.getAttribute(POSITION_ATTR);

            if (o.canRead()) {
                DictionaryImporter importer = null;
                if (name.endsWith(INSTANCE_EXT)) {
                    importer = instantiateImporter(o);
                }
                if (importer != null) {
                    fs.add(new ImporterEntry(importer, position));
                }
            }
        }
        Collections.sort(fs);
        return fs;
    }

    public void fileFolderCreated(FileEvent fe) {
        fileSystemChanged();
    }

    public void fileDataCreated(FileEvent fe) {
        fileSystemChanged();
    }

    public void fileChanged(FileEvent fe) {
        fileSystemChanged();
    }

    public void fileDeleted(FileEvent fe) {
        fileSystemChanged();
    }

    public void fileRenamed(FileRenameEvent fe) {
        fileSystemChanged();
    }

    public void fileAttributeChanged(FileAttributeEvent fe) {
        fileSystemChanged();
    }

    private void fileSystemChanged() {
        refreshFs.cancel();
        refreshFs.schedule(50);
    }
    private final RequestProcessor.Task refreshFs =
            new RequestProcessor(DictionaryImporterManager.class.getName()).create(new Runnable() {

        public void run() {
            doInit();
        }
    });

    private static class ImporterEntry implements Comparable<ImporterEntry> {

        private final DictionaryImporter importer;
        private final Integer position;

        public ImporterEntry(DictionaryImporter importer, Integer position) {
            this.importer = importer;
            this.position = position;
        }

        public DictionaryImporter getImporter() {
            return importer;
        }

        public Integer getPosition() {
            return position;
        }

        public int compareTo(ImporterEntry o) {
            return position.compareTo(o.getPosition());
        }
    }
}
